#include <alsa/asoundlib.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <unistd.h>

// WAV文件头结构
#pragma pack(push, 1)
struct WavHeader {
    char riff[4] = {'R', 'I', 'F', 'F'};
    uint32_t fileSize = 0;
    char wave[4] = {'W', 'A', 'V', 'E'};
    char fmt[4] = {'f', 'm', 't', ' '};
    uint32_t fmtSize = 16;
    uint16_t audioFormat = 1; // PCM = 1
    uint16_t numChannels = 0;
    uint32_t sampleRate = 0;
    uint32_t byteRate = 0;
    uint16_t blockAlign = 0;
    uint16_t bitsPerSample = 0;
    char data[4] = {'d', 'a', 't', 'a'};
    uint32_t dataSize = 0;
};
#pragma pack(pop)

int main() {
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    unsigned int sampleRate = 44100;
    int channels = 1;
    snd_pcm_uframes_t frames = 1024;
    char *buffer;
    int err;
    const char* outputFile = "output.wav";

    // 打开PCM设备
    if ((err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0) {
        std::cerr << "无法打开PCM设备: " << snd_strerror(err) << std::endl;
        return -1;
    }

    // 分配并填充硬件参数
    snd_pcm_hw_params_alloca(&params);
    snd_pcm_hw_params_any(handle, params);
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(handle, params, channels);
    snd_pcm_hw_params_set_rate_near(handle, params, &sampleRate, 0);
    snd_pcm_hw_params_set_period_size_near(handle, params, &frames, 0);

    // 应用参数
    if ((err = snd_pcm_hw_params(handle, params)) < 0) {
        std::cerr << "无法设置硬件参数: " << snd_strerror(err) << std::endl;
        snd_pcm_close(handle);
        return -1;
    }

    // 获取实际参数
    unsigned int actualRate;
    snd_pcm_hw_params_get_rate(params, &actualRate, 0);
    if (actualRate != sampleRate) {
        std::cout << "警告: 采样率不匹配。请求: " << sampleRate 
                  << ", 实际: " << actualRate << std::endl;
        sampleRate = actualRate;
    }

    // 计算缓冲区大小
    snd_pcm_hw_params_get_period_size(params, &frames, 0);
    int bufferSize = frames * 2 * channels; // 16位=2字节
    buffer = (char*) malloc(bufferSize);

    // 准备WAV文件头
    WavHeader header;
    header.numChannels = channels;
    header.sampleRate = sampleRate;
    header.bitsPerSample = 16; // 与SND_PCM_FORMAT_S16_LE对应
    header.blockAlign = header.numChannels * header.bitsPerSample / 8;
    header.byteRate = header.sampleRate * header.blockAlign;

    // 打开输出文件
    std::ofstream file(outputFile, std::ios::binary);
    if (!file) {
        std::cerr << "无法创建输出文件" << std::endl;
        free(buffer);
        snd_pcm_close(handle);
        return -1;
    }

    // 写入临时文件头（后续更新大小信息）
    file.write(reinterpret_cast<char*>(&header), sizeof(WavHeader));

    // 开始捕获音频
    std::cout << "开始录音... (按Ctrl+C停止，或等待10秒)" << std::endl;
    uint32_t totalBytesWritten = 0;
    const int maxSeconds = 10;
    const int loops = maxSeconds * sampleRate / frames;

    for (int i = 0; i < loops; i++) {
        err = snd_pcm_readi(handle, buffer, frames);
        if (err == -EPIPE) {
            std::cerr << "欠载发生，正在恢复..." << std::endl;
            snd_pcm_prepare(handle);
        } else if (err < 0) {
            std::cerr << "读取错误: " << snd_strerror(err) << std::endl;
            break;
        } else if (err != (int)frames) {
            std::cerr << "读取不完整" << std::endl;
        }

        // 写入音频数据
        int bytesToWrite = err * header.blockAlign;
        file.write(buffer, bytesToWrite);
        totalBytesWritten += bytesToWrite;

        // 显示进度
        if (i % (loops / 10) == 0) {
            std::cout << "." << std::flush;
        }
    }
    std::cout << std::endl;

    // 更新文件头中的大小信息
    header.dataSize = totalBytesWritten;
    header.fileSize = 36 + totalBytesWritten; // 36 = 整个文件大小 - 8

    // 定位到文件开头并写入更新后的头
    file.seekp(0, std::ios::beg);
    file.write(reinterpret_cast<char*>(&header), sizeof(WavHeader));

    // 清理资源
    file.close();
    free(buffer);
    snd_pcm_drain(handle);
    snd_pcm_close(handle);

    std::cout << "录音完成，已保存为 " << outputFile << std::endl;
    std::cout << "音频格式: WAV (PCM 16位 小端序)" << std::endl;
    std::cout << "采样率: " << sampleRate << " Hz" << std::endl;
    std::cout << "声道数: " << channels << std::endl;

    return 0;
}
